"""
Copyright (c) 2024 lowyyh
command-line-mine-sweeping is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
import os
import random
import colorama
# import pygame


# 定义游戏类
class Minesweeper:
    def __init__(self):
        self.board = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]  # 数字
        self.mines = []  # 地雷列表
        self.show = []  # 已显示
        self.flags = []  # 标记
        self.game_over = False  # 失败
        self.victory = False  # 胜利

        # 生成地雷
        long = 0
        while long != MINE_COUNT:
            x = random.randint(0, WIDTH - 1)
            y = random.randint(0, HEIGHT - 1)
            if (x, y) not in self.mines:
                self.mines.append((x, y))
                long += 1
            else:
                pass

        # 计算数字
        for x in range(WIDTH):
            for y in range(HEIGHT):
                if (x, y) not in self.mines:
                    count = 0
                    for dx in range(-1, 2):
                        for dy in range(-1, 2):
                            if 0 <= x + dx < WIDTH and 0 <= y + dy < HEIGHT and (x + dx, y + dy) in self.mines:
                                count += 1
                    self.board[y][x] = count

    def reveal(self, x, y, num=0):
        try:
            if self.game_over or self.victory or (x, y) in self.flags:
                # print("find out")
                return
            elif (x, y) in self.mines:
                if num == 0:
                    self.game_over = True
                    return
                else:
                    pass
            elif (x, y) not in self.show:
                self.show.append((x, y))

            if num <= 3:
                if self.board[y][x] == 0:
                    for dx in range(-1, 3):
                        for dy in range(-1, 3):
                            self.reveal(x + dx, y + dy, num=num + 1)
        except IndexError:
            pass

    def toggle_flag(self, x, y):
        if self.game_over or self.victory:
            return
        else:
           if (x, y) in self.flags:
               del self.flags[(x ,y)]
           else :
               self.flags.append((x, y))

    def draw(self):
        # os.system("cls")
        print(" " * 4 + " | ".join([(GREEN + str(i) + RESET) for i in range(WIDTH)]) + " |")
        print(" " * 3 + "---|" * WIDTH)
        for y in range(HEIGHT):
            row = GREEN + "{:<4}".format(str(y)) + RESET
            for x in range(WIDTH):
                if (x, y) in self.show:
                    if (x, y) in self.mines:
                        row += RED + "*" + RESET + " | "
                    else:
                        row += str(self.board[y][x]) + " | "
                elif (x, y) in self.flags:
                    row += BLUE + "*" + RESET + " | "
                else:
                    row += "  | "
            print(row)
            print(" " * 3 + "---|" * WIDTH)

    def end(self):
        # os.system("cls")
        print(" " * 4 + " | ".join([(GREEN + str(i) + RESET) for i in range(WIDTH)]) + " |")
        print(" " * 3 + "---|" * WIDTH)
        for y in range(HEIGHT):
            row = GREEN + "{:<4}".format(str(y)) + RESET
            for x in range(WIDTH):
                if (x, y) in self.mines:
                    row += RED + "*" + RESET + " | "
                else:
                    row += str(self.board[y][x]) + " | "
            print(row)
            print(" " * 3 + "---|" * WIDTH)

    def v(self):
        win = []
        for x in range(WIDTH):
            for y in range(HEIGHT):
                if (x, y) not in self.show:
                    win.append((x, y))

        if MINE_COUNT == len(win):
            for i in self.mines:
                if i in win:
                    pass
                else:
                    return
            else:
                print("You win!")
                self.end()
                exit()

    def play(self):
        # for x in range(WIDTH):
        #     for y in range(HEIGHT):
        #         if (x, y) not in self.mines:
        #             print(x, y)
        while not self.game_over and not self.victory:
            self.draw()
            command = input("Enter command (reveal[选择]/flag[标记]/quit[退出]) > ")
            if command == "quit" or command == "q":
                break
            try:
                try:
                    action, x_and_y = command.split(' ')
                    x, y = x_and_y.split(',')
                except ValueError:
                    action = "reveal"
                    x, y = command.split(',')
                x, y = int(x), int(y)
                if (action == "reveal" or action == "r") and (x, y) not in self.show:
                    self.reveal(x, y)
                elif action == "flag" or action == "f":
                    self.toggle_flag(x, y)
                else :
                    continue

                # 胜负判断
                if self.game_over:
                    print("Game over!")
                    self.end()
                    exit()
                elif self.victory:
                    print("You win!")
                    self.end()
                    exit()
                else:
                    if MINE_COUNT == len(self.flags):
                        for i in self.mines:
                            if i in self.flags:
                                pass
                            else :
                                self.v()
                                break
                        else :
                            print("You win!")
                            self.end()
                            exit()

                    self.v()

            except ValueError:
                print("Invalid command")
        print("Game over!")
        self.end()
        # pygame.quit()


if __name__ == '__main__':
    # 初始化 pygame
    # pygame.init()

    # 定义游戏常量
    WIDTH = 9
    HEIGHT = 9
    MINE_COUNT = 10  # 地雷数

    # 定义颜色常量
    colorama.init()
    RESET = colorama.Style.RESET_ALL
    RED = colorama.Fore.RED
    GREEN = colorama.Fore.GREEN
    YELLOW = colorama.Fore.YELLOW
    BLUE = colorama.Fore.BLUE
    MAGENTA = colorama.Fore.MAGENTA
    CYAN = colorama.Fore.CYAN
    WHITE = colorama.Fore.WHITE

    # 开始游戏
    start = Minesweeper()
    start.play()
